from django.contrib.auth import *
from django.contrib.auth.mixins import *
from django_redis import get_redis_connection
from libs.captcha.captcha import captcha
from django.shortcuts import *
from django.views import View
from django.http.response import *
import re
from users.models import User
from django.db import DatabaseError
from django.urls import reverse
from utils.response_code import RETCODE
import logging
logger = logging.getLogger('django_log')
from random import randint
from libs.yuntongxun.sms import CCP
from home.models import *
# Create your views here.


# 注册视图
# 注册页面
class RegisterView(View):
    # 注册页面展示
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):
        # 1接受用户数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        # 2验证数据
        # 2-1 验证数据是否齐全
        if not all([mobile, password, password2, sms_code]):
            return HttpResponseBadRequest('缺少必要的参数')

        # 2-2手机号格式是否正确
        if not re.match(r'^1[3-9]\d{9}', mobile):
            return HttpResponseBadRequest('手机号码格式不正确')
        # 2-3密码是否符合格式
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseBadRequest('请输入8-20位密码，密码是数字，字母')
        # 2-4 密码和确认密码要一致
        if password != password2:
            return HttpResponseBadRequest('两次密码不一致')
        # 2-5 短信验证码是否和redis中的一致
        redis_conn = get_redis_connection('default')
        redis_sms_code = redis_conn.get('sms:%s' % mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码已过期')
        if sms_code != redis_sms_code.decode():
            return HttpResponseBadRequest('短信验证码不一致')
        # 3.保存注册信息
        # create_user 可以使用系统的方法来对密码进行加密
        try:
            user = User.objects.create_user(username=mobile,
                                            mobile=mobile,
                                            password=password)
        except DatabaseError as e:
            logger.error(e)
            return HttpResponseBadRequest('注册失败')

        from django.contrib.auth import login
        login(request, user)
        # 4.返回响应跳转到指定页面
        # 暂时返回一个注册成功的信息，后期再实现跳转到指定页面

        # redirect 是进行重定向
        # reverse 是可以通过 namespace:name 来获取到视图所对应的路由
        response = redirect(reverse('home:index'))
        # return HttpResponse('注册成功，重定向到首页')

        # 设置cookie信息，以方便首页中 用户信息展示的判断和用户信息的展示
        response.set_cookie('is_login', True)
        response.set_cookie('login_name', user.username, max_age=7 * 24 * 3600)

        return response

# 验证码视图

class ImageView(View):
    def get(self, request):
        '''
        步骤：
        1、接收前端传递过来的uuid
        2、判断uuid失分获取到
        3、通过调用captcha来生成图片验证码（返回：图片内容和图片二进制）
        4、将图片内容保存到redis中。uuid作为key，图片内容作为值，同时还需要设置一个过期时间
        5、返回图片给前端
        :param request:
        :return:
        '''

        # 1、接收前端传递过来的uuid
        uuid = request.GET.get('uuid')
        # 2、判断uuid失分获取到
        if uuid is None:
            return HttpResponseBadRequest('没有获取到uuid')
        # 3、通过调用captcha来生成图片验证码（返回：图片内容和图片二进制）
        txt, image = captcha.generate_captcha()
        # 4、将图片内容保存到redis中。uuid作为key，图片内容作为值，同时还需要设置一个过期时间
        redis_conn = get_redis_connection('default')
        # name:数据key，这里采用img前缀：uuid
        # time:300秒后过期
        # value：对应key的值
        redis_conn.setex(name='img:%s' % uuid, time=300, value=txt)
        # 5、返回图片给前端
        return HttpResponse(image, content_type='image/jpeg')

# 发送短信验证码视图

class SmsCodeView(View):

    def get(self, request):
        """
        1.接收参数
        2.参数的验证
            2.1 验证参数是否齐全
            2.2 图片验证码的验证
                连接redis，获取redis中的图片验证码
                判断图片验证码是否存在
                如果图片验证码未过期，我们获取到之后就可以删除图片验证码
                比对图片验证码
        3.生成短信验证码
        4.保存短信验证码到redis中
        5.发送短信
        6.返回响应
        :param request:
        :return:
        """
        # 1.接收参数 （查询字符串的形式传递过来）mobile手机号，image_code图片验证码，uuid唯一，uuid为key
        mobile = request.GET.get('mobile')
        image_code = request.GET.get('image_code')
        uuid = request.GET.get('uuid')
        # 2.参数的验证
        #     2.1 验证参数是否齐全
        if not all([mobile, image_code, uuid]):
            return JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '缺少必要的参数'})
        #     2.2 图片验证码的验证
        #         连接redis，获取redis中的图片验证码
        redis_conn = get_redis_connection('default')
        redis_image_code = redis_conn.get('img:%s' % uuid)
        #         判断图片验证码是否存在
        if redis_image_code is None:
            return JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图片验证码已过期'})
        #         如果图片验证码未过期，我们获取到之后就可以删除图片验证码
        try:
            redis_conn.delete('img:%s' % uuid)
        except Exception as e:
            logger.error(e)
        #         比对图片验证码, 注意大小写的问题， redis的数据是bytes类型
        if redis_image_code.decode().lower() != image_code.lower():
            return JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图片验证码错误'})
        # 3.生成短信验证码
        sms_code = '%06d' % randint(0, 999999)
        # 为了后期比对方便，我们可以将短信验证码记录到日志中
        logger.info(sms_code)
        # 4.保存短信验证码到redis中
        redis_conn.setex('sms:%s' % mobile, 300, sms_code)
        # 5.发送短信
        # 参数1： 测试手机号
        # 参数2：模板内容列表： {1} 短信验证码   {2} 分钟有效
        # 参数3：模板 免费开发测试使用的模板ID为1
        ccp = CCP()
        ccp.send_template_sms(mobile, [sms_code, 5], 1)
        # 6.返回响应
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '短信发送成功'})

import json
# 登录视图
class LoginView(View):
    '''
          实现思路：
          1、接收提交参数
          2、验证参数
           2-1、手机号码是否符合规则
           2-2、密码是否符合规则
          3、用户认证登录
          4、状态保持
          5、根据用户选择的是否记住登录状态进行判断
          6、设置cookie信息，为首页显示服务
          7、跳转到首页
          :param request:
          :return:
          '''
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        # 1接收提交参数
        username = request.POST.get('mobile')
        password = request.POST.get('password')
        remember = request.POST.get('remember')
        #2验证参数
        if not all([username,password]):
            return render(request,template_name='login.html',context={'msg':'账号或密码不能为空'})
        #2-1手机号码是否符合规则
        if not re.match('1[3-9]\d{9}$',username):
            return render(request,template_name='login.html',context={'msg':'手机号码格式不正确'})
        #2-2密码是否符合规则
        if not re.match('^[a-z0-9A-Z]{8,20}$',password):
            return render(request,template_name='login.html',context={'msg':'密码格式不正确'})
        #3用户认证登录
        #采用系统自带的认证方法进行认证
        #默认的认证方法是：针对于username字段进行用户名的判断，当前的判断信息是“手机号”，我们需要修改一下认证
        return_user = authenticate(mobile=username,password=password)
        #判断如果是None，就表示用户名或密码是错误的
        if return_user is None :
            return render(request, template_name='login.html', context={'msg': '账号或密码错误'})
        # 4状态保持
        login(request,return_user)

        #5页面跳转
        #6根据用户选择的是否记住登录状态进行判断
        #设置cookie信息，为显示首页服务
        #根据
        next_page = request.GET.get('next')
        if next_page:
            resp = redirect(next_page)
        else:
            resp = redirect(reverse('home:index'))

        if remember != 'on': #用户没有勾选复选框
            #如果username是中文，设置cookie会报错
            #cookie中文编码处理
            resp.set_cookie('is_login',True)

            username=json.dumps(return_user.username)

            resp.set_cookie('login_name', username)

            request.session.set_expiry(0)#表示浏览器关闭时清楚
            # 设置两周内的cookie
        else:
            username = json.dumps(return_user.username)
            resp.set_cookie('is_login', True,max_age=24*360*14)
            resp.set_cookie('login_name', username,max_age=24*60*14)
            request.session.set_expiry(None)#表示默认时长，默认就是2周时间
        return resp
# 退出登录视图
from django.contrib.auth import logout # 导入django自带退出包

class LogoutView(View):
    def get(self,request):
        '''
        实现思路：
        1、清除session数据
        2、删除cookie数据
        3、跳转到首页
        :param request
        : :return:
        '''
        # 实现思路：
        # 1、清除session数据
        logout(request)
        # 2、删除cookie数据
        resp = redirect(reverse('home:index'))
        resp.delete_cookie('is_login')
        resp.delete_cookie('login_name')
        # 3、跳转到首页
        return resp

#找回密码视图
class ForgetPasswordView(View):
    def get(self, request):
        return render(request, 'forget_password.html')

    def post(self, request):
        # 接收参数
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        smscode = request.POST.get('sms_code')

        # 判断参数是否齐全
        if not all([mobile, password, password2, smscode]):
            return HttpResponseBadRequest('缺少必传参数')

        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('请输入正确的手机号码')

        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseBadRequest('请输入8-20位的密码')

        # 判断两次密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次输入的密码不一致')

        # 验证短信验证码
        redis_conn = get_redis_connection('default')
        sms_code_server = redis_conn.get('sms:%s' % mobile)
        if sms_code_server is None:
            return HttpResponseBadRequest('短信验证码已过期')
        if smscode != sms_code_server.decode():
            return HttpResponseBadRequest('短信验证码错误')

        # 根据手机号查询数据
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 如果该手机号不存在，则注册个新用户
            try:
                User.objects.create_user(username=mobile, mobile=mobile, password=password)
            except Exception:
                return HttpResponseBadRequest('修改失败，请稍后再试')
        else:
            # 修改用户密码
            user.set_password(password)
            user.save()

        # 跳转到登录页面
        response = redirect('/login')

        return response

#个人中心视图
#方法一
# print(request.user.is_authenticated)
# if not request.user.is_authenticated:
#     return  redirect(reverse('users:login'))
class UserCenterView(LoginRequiredMixin,View):
    def get(self,request):
        #获取已经登录用户对象
        userinfo = request.user
        content={
            'username':userinfo.username,
            'mobile':userinfo.mobile,
            'avatar': userinfo.avatar.url if userinfo.avatar else None,
            'user_desc':userinfo.user_desc,
        }
        return render(request,'usercenter.html',context=content)

    def post(self,request):
        '''
        实现思路：
        1、接收用户参数
        2、将用户参数更新到数据库
        3、更新cookie中的username
        4、刷新当前页面（重定向操作）
        5、返回相应
        :param request:
        :return:
        '''
        # 获取已经登录用户对象
        userinfo = request.user
        # 1、接收用户参数
        # 获取用户提交的用户名，如果没有就将已登录的用户名赋值
        username = request.POST.get('username',userinfo.username)
        # 获取用户提交的介绍，如果没有就将已登录的介绍赋值
        user_desc = request.POST.get('desc',userinfo.user_desc)

        # 获取用户头像(如果没有图片保存地址，则会默认保存到项目的根目录下。否则需要在settting中进行配置地址
        avatar = request.FILES.get('avatar')
        # 2、将用户参数更新到数据库
        try:
            userinfo.username = username
            userinfo.user_desc = user_desc
            if avatar:
                userinfo.avatar = avatar
            userinfo.save()
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('修改用户信息失败')
        # 3、更新cookie中的username
        # 4、刷新当前页面（重定向操作）
        # return render(request,'usercenter.html')
        resp = redirect(reverse('home:index'))
        username = json.dumps(username)
        resp.set_cookie('login_name',username)
        #5返回响应
        return resp


#写博客页视图
from home.models import *
class WriteBlogView(LoginRequiredMixin,View):
    def get(self,request):
        #获取博客分类信息
        categories = ArticleCategory.objects.all()
        context = {
            'categories':categories
        }
        return render(request,'writeblog.html',context=context)
    def post(self,request):
        '''
        实现思路：
        1、接收数据
        2、验证数据
        3、数据入库
        4、跳转到指定页面
        :param request:
        :return:
        '''
        # 1、接收数据
        avatar = request.FILES.get('avatar')
        title = request.POST.get('title')
        category_id = request.POST.get('category')
        tags = request.POST.get('tags')
        sumary = request.POST.get('sumary')
        content = request.POST.get('content')
        user = request.user
        # 2、验证数据
        # 2-1、参数齐全验证
        if not all([avatar, title, category_id, sumary, content]):
            return HttpResponseBadRequest('参数不齐全')
        # 2-2、判断分类id
        try:
            category = ArticleCategory.objects.filter(pk=category_id).first()
        except ArticleCategory.DoesNotExist:
            return HttpResponseBadRequest('没有该分类信息')
        # 3、数据入库
        try:
            Article.objects.create(author=user,
                                    title=title,
                                    avatar=avatar,
                                    category=category,
                                    tags=tags,
                                    sumary=sumary,
                                    content=content
                                   )
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('发布失败，请稍后重试')
        # 4、跳转到指定页面
        return redirect(reverse('home:index'))

